﻿using MLModel_ConsoleApp1;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using WMSSystem.WYJ;
using WMSSystem.YSL.Dto.PredictionDto;
using System.IO;
using Microsoft.ML;
using Microsoft.ML.Data;

namespace WMSSystem.YSL
{
    /// <summary>
    /// 预测应用服务实现
    /// </summary>
    public class PredictionAppService : ApplicationService
    {
        private readonly IRepository<WYJ_SalesOrder, Guid> _salesOrderRepository;
        private readonly ILogger<PredictionAppService> _logger;
        
        // CSV文件路径配置
        private const string DataFilePath = "wwwroot/AppWYJ_SalesOrder_split_added.csv";
        private const char SeparatorChar = ',';
        private const bool HasHeader = true;
        private const bool AllowQuoting = false;

        public PredictionAppService(
            IRepository<WYJ_SalesOrder, Guid> salesOrderRepository,
            ILogger<PredictionAppService> logger)
        {
            _salesOrderRepository = salesOrderRepository;
            _logger = logger;
        }

        /// <summary>
        /// 根据开始日期和结束日期进行预测，返回包含历史数据和预测数据的列表
        /// </summary>
        /// <param name="startDate">开始日期</param>
        /// <param name="endDate">结束日期</param>
        /// <returns>预测结果列表</returns>
        public async Task<List<PredictionOutputDto>> GetPredictionAsync(DateTime startDate, DateTime endDate)
        {
            try
            {
                _logger.LogInformation("开始预测订单金额，时间范围：{StartDate} 到 {EndDate}",
                    startDate.ToString("yyyy-MM-dd"),
                    endDate.ToString("yyyy-MM-dd"));

                var result = new List<PredictionOutputDto>();

                // 1. 从CSV文件获取历史数据
                var historicalData = await GetHistoricalDataFromFileAsync(startDate, endDate);
                result.AddRange(historicalData);

                _logger.LogInformation("从文件中获取到 {Count} 条历史数据", historicalData.Count);

                // 2. 生成预测数据
                var predictedData = GeneratePredictedData(startDate, endDate);
                result.AddRange(predictedData);

                _logger.LogInformation("生成了 {Count} 条预测数据", predictedData.Count);

                // 3. 合并历史数据和预测数据，按日期分组
                var mergedResult = MergeHistoricalAndPredictedData(result);

                _logger.LogInformation("预测完成，总共返回 {TotalCount} 条数据", mergedResult.Count);

                return mergedResult;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "预测过程中发生错误");
                throw new Exception("预测失败：" + ex.Message, ex);
            }
        }

        /// <summary>
        /// 获取指定月份的预测数据
        /// </summary>
        /// <param name="year">年份</param>
        /// <param name="month">月份</param>
        /// <returns>预测结果列表</returns>
        public async Task<List<PredictionOutputDto>> GetMonthlyPredictionAsync(int year, int month)
        {
            var startDate = new DateTime(year, month, 1);
            var endDate = startDate.AddMonths(1).AddDays(-1);

            return await GetPredictionAsync(startDate, endDate);
        }

        /// <summary>
        /// 获取指定年份的预测数据
        /// </summary>
        /// <param name="year">年份</param>
        /// <returns>预测结果列表</returns>
        public async Task<List<PredictionOutputDto>> GetYearlyPredictionAsync(int year)
        {
            var startDate = new DateTime(year, 1, 1);
            var endDate = new DateTime(year, 12, 31);

            return await GetPredictionAsync(startDate, endDate);
        }

        /// <summary>
        /// 获取预测服务状态
        /// </summary>
        /// <returns>服务状态信息</returns>
        public object GetStatus()
        {
            return new
            {
                Status = "Running",
                Service = "PredictionAppService",
                Message = "预测服务运行正常",
                DataSource = "CSV文件",
                DataFilePath = DataFilePath,
                Timestamp = DateTime.Now
            };
        }

        /// <summary>
        /// 从CSV文件获取历史数据
        /// </summary>
        /// <param name="startDate">开始日期</param>
        /// <param name="endDate">结束日期</param>
        /// <returns>历史数据列表</returns>
        private async Task<List<PredictionOutputDto>> GetHistoricalDataFromFileAsync(DateTime startDate, DateTime endDate)
        {
            try
            {
                // 获取应用程序根目录
                var webRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
                var fullFilePath = Path.Combine(webRootPath, "AppWYJ_SalesOrder_split_added.csv");
                
                _logger.LogInformation("尝试读取CSV文件：{FilePath}", fullFilePath);
                
                // 检查文件是否存在
                if (!File.Exists(fullFilePath))
                {
                    var errorMessage = $"CSV数据文件不存在：{fullFilePath}。请确保文件存在于正确位置。";
                    _logger.LogError(errorMessage);
                    throw new FileNotFoundException(errorMessage);
                }

                // 检查文件是否可读
                try
                {
                    using (var testReader = new StreamReader(fullFilePath, Encoding.UTF8))
                    {
                        var firstLine = await testReader.ReadLineAsync();
                        _logger.LogInformation("文件读取测试成功，第一行：{FirstLine}", firstLine);
                    }
                }
                catch (Exception ex)
                {
                    var errorMessage = $"无法读取CSV文件：{fullFilePath}。错误：{ex.Message}";
                    _logger.LogError(ex, errorMessage);
                    throw new IOException(errorMessage, ex);
                }

                var historicalData = new List<PredictionOutputDto>();
                
                // 读取CSV文件
                using (var reader = new StreamReader(fullFilePath, Encoding.UTF8))
                {
                    string line;
                    bool isFirstLine = true;
                    int lineNumber = 0;
                    
                    while ((line = await reader.ReadLineAsync()) != null)
                    {
                        lineNumber++;
                        
                        // 跳过标题行
                        if (isFirstLine && HasHeader)
                        {
                            _logger.LogDebug("跳过标题行：{HeaderLine}", line);
                            isFirstLine = false;
                            continue;
                        }

                        try
                        {
                            // 解析CSV行
                            var values = ParseCsvLine(line);
                            if (values.Length >= 4) // 确保有足够的列
                            {
                                // 解析日期和金额
                                if (float.TryParse(values[0], out float year) &&
                                    float.TryParse(values[1], out float month) &&
                                    float.TryParse(values[2], out float day) &&
                                    float.TryParse(values[3], out float orderMoney))
                                {
                                    // 构建日期
                                    var date = new DateTime((int)year, (int)month, (int)day);
                                    
                                    // 检查日期是否在指定范围内
                                    if (date >= startDate && date <= endDate)
                                    {
                                        historicalData.Add(new PredictionOutputDto
                                        {
                                            Date = date,
                                            Year = (int)year,
                                            Month = (int)month,
                                            Day = (int)day,
                                            ActualOrderMoney = orderMoney,
                                            PredictedOrderMoney = 0,
                                            DataType = "Historical"
                                        });
                                    }
                                }
                                else
                                {
                                    _logger.LogWarning("第 {LineNumber} 行数据格式错误：{Line}", lineNumber, line);
                                }
                            }
                            else
                            {
                                _logger.LogWarning("第 {LineNumber} 行列数不足，期望4列，实际{ColumnCount}列：{Line}", 
                                    lineNumber, values.Length, line);
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogWarning(ex, "解析第 {LineNumber} 行时发生错误：{Line}", lineNumber, line);
                            continue; // 跳过错误的行
                        }
                    }
                }

                // 按日期分组并汇总
                var groupedData = historicalData
                    .GroupBy(x => x.Date.Date)
                    .Select(g => new PredictionOutputDto
                    {
                        Date = g.Key,
                        Year = g.Key.Year,
                        Month = g.Key.Month,
                        Day = g.Key.Day,
                        ActualOrderMoney = g.Sum(x => x.ActualOrderMoney),
                        PredictedOrderMoney = 0,
                        DataType = "Historical"
                    })
                    .OrderBy(x => x.Date)
                    .ToList();

                _logger.LogInformation("成功从文件获取 {Count} 条历史数据，时间范围：{StartDate} 到 {EndDate}",
                    groupedData.Count,
                    startDate.ToString("yyyy-MM-dd"),
                    endDate.ToString("yyyy-MM-dd"));

                return groupedData;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "从文件获取历史数据时发生错误，时间范围：{StartDate} 到 {EndDate}",
                    startDate.ToString("yyyy-MM-dd"),
                    endDate.ToString("yyyy-MM-dd"));
                throw;
            }
        }

        /// <summary>
        /// 生成模拟历史数据
        /// </summary>
        /// <param name="startDate">开始日期</param>
        /// <param name="endDate">结束日期</param>
        /// <returns>模拟历史数据列表</returns>
        private async Task<List<PredictionOutputDto>> GenerateMockHistoricalDataAsync(DateTime startDate, DateTime endDate)
        {
            try
            {
                var mockData = new List<PredictionOutputDto>();
                var random = new Random(42); // 固定种子确保可重现性
                var currentDate = startDate;

                while (currentDate <= endDate)
                {
                    // 生成每天1-5个订单的模拟数据
                    var dailyOrderCount = random.Next(1, 6);
                    var dailyTotalAmount = 0f;

                    for (int i = 0; i < dailyOrderCount; i++)
                    {
                        // 生成1000-50000之间的随机订单金额
                        var orderAmount = (float)(random.Next(1000, 50000) + random.NextDouble() * 1000);
                        dailyTotalAmount += orderAmount;
                    }

                    mockData.Add(new PredictionOutputDto
                    {
                        Date = currentDate,
                        Year = currentDate.Year,
                        Month = currentDate.Month,
                        Day = currentDate.Day,
                        ActualOrderMoney = dailyTotalAmount,
                        PredictedOrderMoney = 0,
                        DataType = "Historical"
                    });

                    currentDate = currentDate.AddDays(1);
                }

                _logger.LogInformation("成功生成 {Count} 条模拟历史数据，时间范围：{StartDate} 到 {EndDate}",
                    mockData.Count,
                    startDate.ToString("yyyy-MM-dd"),
                    endDate.ToString("yyyy-MM-dd"));

                return mockData;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "生成模拟历史数据时发生错误");
                throw;
            }
        }

        /// <summary>
        /// 解析CSV行
        /// </summary>
        /// <param name="line">CSV行</param>
        /// <returns>解析后的值数组</returns>
        private string[] ParseCsvLine(string line)
        {
            var values = new List<string>();
            var currentValue = new StringBuilder();
            bool inQuotes = false;
            
            for (int i = 0; i < line.Length; i++)
            {
                char c = line[i];
                
                if (c == '"')
                {
                    inQuotes = !inQuotes;
                }
                else if (c == SeparatorChar && !inQuotes)
                {
                    values.Add(currentValue.ToString().Trim());
                    currentValue.Clear();
                }
                else
                {
                    currentValue.Append(c);
                }
            }
            
            // 添加最后一个值
            values.Add(currentValue.ToString().Trim());
            
            return values.ToArray();
        }

        /// <summary>
        /// 生成预测数据
        /// </summary>
        /// <param name="startDate">开始日期</param>
        /// <param name="endDate">结束日期</param>
        /// <returns>预测数据列表</returns>
        private List<PredictionOutputDto> GeneratePredictedData(DateTime startDate, DateTime endDate)
        {
            try
            {
                var predictedData = new List<PredictionOutputDto>();
                var currentDate = startDate;

                while (currentDate <= endDate)
                {
                    try
                    {
                        // 使用ML.NET模型进行预测
                        var modelInput = new MLModel.ModelInput
                        {
                            Year = currentDate.Year,
                            Month = currentDate.Month,
                            Day = currentDate.Day
                        };

                        var prediction = MLModel.Predict(modelInput);

                        predictedData.Add(new PredictionOutputDto
                        {
                            Date = currentDate,
                            Year = currentDate.Year,
                            Month = currentDate.Month,
                            Day = currentDate.Day,
                            // 预测金额赋值给预测数据
                            PredictedOrderMoney = prediction.Score,
                            // 历史金额为null，因为这是预测数据
                            ActualOrderMoney = null,
                            DataType = "Predicted"
                        });
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "预测日期 {Date} 时发生错误，跳过该日期", currentDate.ToString("yyyy-MM-dd"));

                        // 如果预测失败，添加一个默认值
                        predictedData.Add(new PredictionOutputDto
                        {
                            Date = currentDate,
                            Year = currentDate.Year,
                            Month = currentDate.Month,
                            Day = currentDate.Day,
                            PredictedOrderMoney = 0,
                            ActualOrderMoney = null,
                            DataType = "Predicted"
                        });
                    }

                    currentDate = currentDate.AddDays(1);
                }

                _logger.LogInformation("成功生成 {Count} 条预测数据，时间范围：{StartDate} 到 {EndDate}",
                    predictedData.Count,
                    startDate.ToString("yyyy-MM-dd"),
                    endDate.ToString("yyyy-MM-dd"));

                return predictedData;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "生成预测数据时发生错误，时间范围：{StartDate} 到 {EndDate}",
                    startDate.ToString("yyyy-MM-dd"),
                    endDate.ToString("yyyy-MM-dd"));
                throw;
            }
        }

        /// <summary>
        /// 合并历史数据和预测数据
        /// </summary>
        /// <param name="allData">所有数据</param>
        /// <returns>合并后的数据</returns>
        private List<PredictionOutputDto> MergeHistoricalAndPredictedData(List<PredictionOutputDto> allData)
        {
            try
            {
                // 按日期分组，合并同一天的历史数据和预测数据
                var mergedData = allData
                    .GroupBy(x => x.Date.Date)
                    .Select(g =>
                    {
                        var historicalData = g.FirstOrDefault(x => x.DataType == "Historical");
                        var predictedData = g.FirstOrDefault(x => x.DataType == "Predicted");

                        return new PredictionOutputDto
                        {
                            Date = g.Key,
                            Year = g.Key.Year,
                            Month = g.Key.Month,
                            Day = g.Key.Day,
                            // 如果有历史数据，使用历史数据；否则为null
                            ActualOrderMoney = historicalData?.ActualOrderMoney,
                            // 如果有预测数据，使用预测数据；否则为0
                            PredictedOrderMoney = predictedData?.PredictedOrderMoney ?? 0,
                            // 根据是否有历史数据确定数据类型
                            DataType = historicalData != null ? "Historical" : "Predicted"
                        };
                    })
                    .OrderBy(x => x.Date)
                    .ToList();

                _logger.LogInformation("成功合并数据，返回 {Count} 条记录", mergedData.Count);

                return mergedData;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "合并历史数据和预测数据时发生错误");
                throw;
            }
        }

        /// <summary>
        /// 检查数据文件状态
        /// </summary>
        /// <returns>文件状态信息</returns>
        public object CheckDataFileStatus()
        {
            try
            {
                var webRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
                var fullFilePath = Path.Combine(webRootPath, "AppWYJ_SalesOrder_split_added.csv");
                
                var fileExists = File.Exists(fullFilePath);
                var fileInfo = fileExists ? new FileInfo(fullFilePath) : null;
                
                return new
                {
                    FileExists = fileExists,
                    FilePath = fullFilePath,
                    RelativePath = "wwwroot/AppWYJ_SalesOrder_split_added.csv",
                    FileSize = fileInfo?.Length ?? 0,
                    LastModified = fileInfo?.LastWriteTime,
                    CanRead = fileExists ? File.Exists(fullFilePath) : false,
                    Status = fileExists ? "正常" : "文件不存在",
                    RowCount = fileExists ? GetFileRowCount(fullFilePath) : 0
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "检查数据文件状态时发生错误");
                return new
                {
                    FileExists = false,
                    FilePath = "wwwroot/AppWYJ_SalesOrder_split_added.csv",
                    Error = ex.Message,
                    Status = "检查失败"
                };
            }
        }

        /// <summary>
        /// 获取CSV文件的行数
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>行数</returns>
        private int GetFileRowCount(string filePath)
        {
            try
            {
                var lineCount = 0;
                using (var reader = new StreamReader(filePath, Encoding.UTF8))
                {
                    while (reader.ReadLine() != null)
                    {
                        lineCount++;
                    }
                }
                // 减去标题行
                return HasHeader ? lineCount - 1 : lineCount;
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// 测试CSV文件读取
        /// </summary>
        /// <returns>测试结果</returns>
        public async Task<object> TestCsvFileReadingAsync()
        {
            try
            {
                var webRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
                var fullFilePath = Path.Combine(webRootPath, "AppWYJ_SalesOrder_split_added.csv");
                
                var result = new
                {
                    FilePath = fullFilePath,
                    FileExists = File.Exists(fullFilePath),
                    CurrentDirectory = Directory.GetCurrentDirectory(),
                    WebRootPath = webRootPath
                };

                if (File.Exists(fullFilePath))
                {
                    var fileInfo = new FileInfo(fullFilePath);
                    var firstFewLines = new List<string>();
                    
                    using (var reader = new StreamReader(fullFilePath, Encoding.UTF8))
                    {
                        for (int i = 0; i < 5 && !reader.EndOfStream; i++)
                        {
                            var line = await reader.ReadLineAsync();
                            firstFewLines.Add(line);
                        }
                    }

                    return new
                    {
                        Success = true,
                        FilePath = fullFilePath,
                        FileSize = fileInfo.Length,
                        LastModified = fileInfo.LastWriteTime,
                        FirstFewLines = firstFewLines,
                        Message = "文件读取成功"
                    };
                }
                else
                {
                    return new
                    {
                        Success = false,
                        FilePath = fullFilePath,
                        Message = "文件不存在",
                        Suggestions = new[]
                        {
                            "请确保文件存在于正确位置",
                            "检查文件路径是否正确",
                            "确保应用程序有读取文件的权限"
                        }
                    };
                }
            }
            catch (Exception ex)
            {
                return new
                {
                    Success = false,
                    Error = ex.Message,
                    StackTrace = ex.StackTrace,
                    Message = "文件读取测试失败"
                };
            }
        }
    }
}